package cn.le.netty.server;

import cn.le.netty.client.handler.EchoClientHandler;
import cn.le.netty.serious.*;
import cn.le.netty.server.handler.EchoServerHandler;
import cn.le.util.info.HostInfo;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.util.CharsetUtil;

import java.nio.charset.Charset;

/**
 * 实现了基础
 */
public class EchoServer {

    //利用ByteBuf接受数据,需要转换比较麻烦
    public void run()throws Exception{
        //线程池是提升服务器性能的重要手段,利用定长的线程池可以保证核线程池的有效数据
        //在netty之中的线程池分为两类:主线程池(接受客户端),工作线程池(处理客户链接)
        EventLoopGroup boosGroup = new NioEventLoopGroup(10);
        EventLoopGroup workGroup = new NioEventLoopGroup(20);
        System.out.println("服务器连接启动成功,监听端口:"+HostInfo.PORT);
        try {
            //创建一个服务器端的程序类进行nio启动,同时可以设置Channel
            ServerBootstrap serverBootstrap = new ServerBootstrap();//服务器端
            //设置要使用的线程池以及当前的channel类型
            serverBootstrap.group(boosGroup, workGroup).channel(NioServerSocketChannel.class);
            //接收到信息之后需要进行处理,于是定义子处理器
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    socketChannel.pipeline().addLast(new LineBasedFrameDecoder(2014));//追加拆包器
                    //追加处理器
                    socketChannel.pipeline().addLast(new EchoServerHandler());
                }
            });
            //可以直接利用常量进行tcp协议的相关配置
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            //ChannelFuture描述的异步回填的处理操作
            ChannelFuture future = serverBootstrap.bind(HostInfo.PORT).sync();
            future.channel().closeFuture().sync();//等待socket被关闭
        }finally {
            workGroup.shutdownGracefully();
            boosGroup.shutdownGracefully();
        }
    }


    public void strRun()throws Exception{
        EventLoopGroup boosGroup = new NioEventLoopGroup(10);
        EventLoopGroup workGroup = new NioEventLoopGroup(20);
        System.out.println("服务器连接启动成功,监听端口:"+HostInfo.PORT);
        try {
            //创建一个服务器端的程序类进行nio启动,同时可以设置Channel
            ServerBootstrap serverBootstrap = new ServerBootstrap();//服务器端
            //设置要使用的线程池以及当前的channel类型
            serverBootstrap.group(boosGroup, workGroup).channel(NioServerSocketChannel.class);
            //接收到信息之后需要进行处理,于是定义子处理器
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //默认拆包处理器 分割标志是系统默认标志System.getProperty("line.separator")
                    //socketChannel.pipeline().addLast(new LineBasedFrameDecoder(1024));//追加拆包器
                    //设置字符编码解码处理器
                    socketChannel.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8));
                    socketChannel.pipeline().addLast(new StringDecoder(CharsetUtil.UTF_8));
                    //追加处理器
                    socketChannel.pipeline().addLast(new EchoServerHandler());
                }
            });
            //可以直接利用常量进行tcp协议的相关配置
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            //ChannelFuture描述的异步回填的处理操作
            ChannelFuture future = serverBootstrap.bind(HostInfo.PORT).sync();
            future.channel().closeFuture().sync();//等待socket被关闭
        }finally {
            workGroup.shutdownGracefully();
            boosGroup.shutdownGracefully();
        }
    }

    public void objRun()throws Exception{
        EventLoopGroup boosGroup = new NioEventLoopGroup(10);
        EventLoopGroup workGroup = new NioEventLoopGroup(20);
        System.out.println("服务器连接启动成功,监听端口:"+HostInfo.PORT);
        try {
            //创建一个服务器端的程序类进行nio启动,同时可以设置Channel
            final ServerBootstrap serverBootstrap = new ServerBootstrap();//服务器端
            //设置要使用的线程池以及当前的channel类型
            serverBootstrap.group(boosGroup, workGroup).channel(NioServerSocketChannel.class);
            //接收到信息之后需要进行处理,于是定义子处理器
            serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    //messagePack 处理器,
                    // 在messagePack解码器之前增加LengthFieldBasedFrameDecoder,用于处理半包消息,
                    //这样后面的messageDecoder接收到的永远是整包消息
                    // 在MessagePack编码器之前增加LengthFieldPrepender,它将在byteBuf
                    //之前增加4个字节的消息长度字段
                    //socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535,0,4,0,4));
                    //socketChannel.pipeline().addLast(new MessagePackDecoder());
                    //socketChannel.pipeline().addLast(new LengthFieldPrepender(4));//与属性的个数保持一致
                    //socketChannel.pipeline().addLast(new MessagePachEncoder());

                    //Marshalling处理器
                    //socketChannel.pipeline().addLast(MarshallingCodeFactory.buildMarshllingDecoder());
                    //socketChannel.pipeline().addLast(MarshallingCodeFactory.builMarshallingEncoder());
                    /*maxFrameLength：帧的最大长度
                    lengthFieldOffset length：字段偏移的地址
                    lengthFieldLength length;字段所占的字节长
                    lengthAdjustment：修改帧数据长度字段中定义的值，可以为负数因为有时候我们习惯把头部记入长度，若为负数，则说明要推后多少个字段
                    initialBytesToStrip：解析时候跳过多少个长度
                    failFast; 为真，当帧长度超过maxFrameLength时立即报TooLongFrameException异常，为假，读取完整个帧再报异*/

                    socketChannel.pipeline().addLast(new LengthFieldBasedFrameDecoder(65535,0,4,
                            0,4));
                    socketChannel.pipeline().addLast(new JSONDecoder());
                    socketChannel.pipeline().addLast(new LengthFieldPrepender(4));
                    socketChannel.pipeline().addLast(new JSONEncoder());
                    socketChannel.pipeline().addLast(new EchoServerHandler());
                }
            });
            //可以直接利用常量进行tcp协议的相关配置
            serverBootstrap.option(ChannelOption.SO_BACKLOG, 128);
            serverBootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            //ChannelFuture描述的异步回填的处理操作
            ChannelFuture future = serverBootstrap.bind(HostInfo.PORT).sync();
            future.channel().closeFuture().sync();//等待socket被关闭
        }finally {
            workGroup.shutdownGracefully();
            boosGroup.shutdownGracefully();
        }
    }
    public static void main(String[] args) throws Exception {
        //new EchoServer().run();
        //new EchoServer().strRun();
        new EchoServer().objRun();
    }

}
